<!-- 1.闭包的概念 -->https://mp.weixin.qq.com/s/m1Rg8-CDmN3MgdnzeriJBA
https://mp.weixin.qq.com/s/zsqfyycvhr711mO2XUK0UQ
<!-- 红宝书（P309）上对于闭包的定义：
闭包指的是那些引用了另一个函数作用域中变量的函数，通常是在嵌套函数中实现的。

MDN对闭包的定义：
闭包是指那些能够访问自由变量的函数。其中自由变量是指在函数中使用的，但既不是函数参数也不是函数的局部变量的变量。

总结一下就是，闭包是指有权访问另一个函数作用域中变量的函数，
创建闭包的最常见的方式就是在一个函数内创建另一个函数，创建的函数可以访问到当前函数的局部变量。 -->



function a(){
  var aa = 666
  function b(){
      var bb = 888
      console.log(aa);  //输出：666
  }
  return b
}
var demo = a()
demo()
a函数调用完之后，该函数执行上下文会被销毁，但是会保留一部分在内存中供b函数使用，这就形成了闭包。

<!-- 闭包的用途： -->
1.封装私有变量，避免全局变量污染:闭包可以用于封装私有变量，以防止其被外部访问和修改。
封装私有变量可以一定程度上防止全局变量污染
function add(){
  let count = 0
  function a(){
      count++
      console.log(count);
  }
  return a
}
var res = add() 
res() //1 
res() //2
res() //3

2做缓存
函数一旦被执行完毕，其内存就会被销毁，而闭包的存在，就可以保有内部环境的作用域。
function foo(){
  var myName ='张三'
  let test1 = 1
  const test2 = 2 
  var innerBar={
      getName: function(){
          console.log(test1);
          return myName
      },
      setName:function(newName){
          myName = newName
      }
  }
  return innerBar
}
var bar = foo()   
console.log(bar.getName()); //输出：1 张三
bar.setName('李四')
console.log(bar.getName()); //输出：1 李四

这里var bar = foo() 执行完后本来应该被销毁，但是因为形成了闭包，所以导致foo执行上下文没有被销毁干净
，被引用了的变量myName、test1没被销毁，
闭包里存放的就是变量myName、test1，这个闭包就像是setName、getName的专属背包，
setName、getName依然可以使用foo执行上下文中的test1和myName。

3.模块化编程（实现共有变量）
闭包可以用于封装模块的私有变量和方法，以便防止其被外部访问和修改。例如：
const myModule = (function() {
  let privateVariable = '我是私有的!';

  function privateMethod() {
    console.log(privateVariable);
  }

  return {
    publicMethod: function() {
      privateMethod();
    }
  };
})();

myModule.publicMethod(); // 输出: 我是私有的!

<!-- 闭包缺点： -->

创建的变量不能被回收，容易消耗内存，使用不当会导致内存溢出
解决： 1.及时释放闭包：手动调用闭包函数，并将其返回值赋值为null，这样可以让闭包中的变量及时被垃圾回收器回收。
2.使用立即执行函数，将所需要保留的变量作为参数传递给闭包函数

function createCounter() {
  const initialValue = 0;

  // Using an IIFE to create a closure with the initialValue variable preserved
  const counter = (function(initial) {
      let count = initial;

      return {
          increment: function() {
              count++;
          },
          decrement: function() {
              count--;
          },
          getCount: function() {
              return count;
          }
      };
  })(initialValue);

  return counter;
}

const myCounter = createCounter();
myCounter.increment();
myCounter.increment();
console.log(myCounter.getCount()); // Output: 2
下面是一个示例，展示了如何手动释放闭包，以避免内存泄漏问题：

```javascript
function outer() {
  var outerVar = 'Hello';

  function inner() {
    console.log(outerVar);
  }

  return inner;
}

var closure = outer();
closure(); // 输出：Hello

// 手动释放闭包
closure = null;
```

在上面的示例中，我们定义了一个`outer`函数，它返回一个内部函数`inner`。然后，我们通过调用`outer`函数，将返回的闭包赋值给变量`closure`。

在执行完闭包后，我们可以手动将`closure`变量赋值为`null`，这样可以解除对闭包的引用，让闭包中的变量及时被垃圾回收器回收。这样可以避免内存泄漏问题。

需要注意的是，手动释放闭包并不是必需的，JavaScript的垃圾回收机制会自动回收不再使用的变量和对象。但是，如果闭包持有的变量是大型对象或者是需要及时释放的资源，手动释放闭包可以更快地释放这些资源，提高内存的利用效率。

总之，为了避免潜在的内存泄漏问题，当不再需要使用闭包时，可以手动将闭包赋值为`null`，以便让闭包中的变量及时被垃圾回收器回收
<!-- 闭包的表现形式 -->
